home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-09-17 | 11.8 KB | 472 lines | [TEXT/MPS ] |
- //========================================================================================
- //
- // File: PRTxtBuf.h
- // Release Version: $ ODF 2 $
- //
- // Modified by MEB to support non-single-byte characters
- //
- // Copyright: (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
-
- #include "FWOS.hpp"
-
- #ifndef PRTXTBUF_H
- #include "PRTxtBuf.h"
- #endif
-
- #ifndef FWMEMORY_H
- #include "FWMemory.h"
- #endif
-
- #ifndef FWSOMENV_H
- #include "FWSOMEnv.h"
- #endif
-
- //========================================================================================
- // RunTime Info
- //========================================================================================
-
- #ifdef FW_BUILD_MAC
- #pragma segment FWGraphx_TextBuf
- #endif
-
- FW_DEFINE_AUTO(FW_CPrivTextBuffer)
-
- //========================================================================================
- // CLASS FW_CPrivTextBuffer
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::FW_CPrivTextBuffer
- //----------------------------------------------------------------------------------------
-
- FW_CPrivTextBuffer::FW_CPrivTextBuffer(FW_HString string) :
- fString(string),
- fReader(NULL),
- fCurrentLine(NULL),
- fCurRun(NULL),
- fCurRunIsLast(FALSE),
- fIsDone(FALSE),
- fIsLastLine(FALSE),
- fDynamicBufferBase(NULL),
- fUsingFixedBuffer(TRUE)
- {
- Advance();
- FW_END_CONSTRUCTOR
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::FW_CPrivTextBuffer
- //----------------------------------------------------------------------------------------
-
- FW_CPrivTextBuffer::FW_CPrivTextBuffer(FW_HTextReader reader) :
- fString(NULL),
- fReader(reader),
- fCurrentLine(NULL),
- fCurRun(NULL),
- fCurRunIsLast(NULL),
- fIsDone(FALSE),
- fIsLastLine(FALSE),
- fUsingFixedBuffer(TRUE),
- fDynamicBufferBase(NULL)
- {
- Advance();
- FW_END_CONSTRUCTOR
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::~FW_CPrivTextBuffer
- //----------------------------------------------------------------------------------------
-
- FW_CPrivTextBuffer::~FW_CPrivTextBuffer()
- {
- FW_START_DESTRUCTOR
- FW_CMemoryManager::FreeBlock(fDynamicBufferBase);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::IsDone
- //----------------------------------------------------------------------------------------
-
- FW_Boolean FW_CPrivTextBuffer::IsDone() const
- {
- return fIsDone;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::Advance
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivTextBuffer::Advance()
- {
- // the user should not call this method after we told hir we're done
- FW_ASSERT(!fIsDone);
-
- // get the next run if we need to
- if (fCurRun == NULL)
- if (!GetNextRun())
- {
- fIsDone = TRUE;
- return;
- }
-
- // search for newline in the current run
- char* p = FindRunNewLine();
-
- if (p != NULL)
- {
- // Found a newline
- fCurrentLine = fCurRunPos;
- fCurrentLineLength = p - fCurRunPos + 1;
- fCurRunPos = p + 1;
- return;
- }
-
- if (fCurRunIsLast)
- {
- // No newline, last run - use the remainder of the run
- fCurrentLine = fCurRunPos;
- fCurrentLineLength = fCurRunLen - (fCurRunPos - fCurRun);
- fIsLastLine = TRUE;
- fIsDone = fCurrentLineLength == 0;
- return;
- }
-
- // No newline, not the last run - consume the run
- ResetBuffer(fCurRunLen - (fCurRunPos - fCurRun));
- AppendToBuffer(fCurRunPos, fCurRunLen - (fCurRunPos - fCurRun));
-
- // Keep going through the runs until we find a newline or the show is over
- while (GetNextRun())
- {
- char* p = FindRunNewLine();
- FW_ByteCount len = p == NULL ? fCurRunLen : p - fCurRunPos + 1;
-
- AppendToBuffer(fCurRunPos, len);
- fCurRunPos += len;
-
- if (p != NULL) // Found a newline
- break;
-
- if (fCurRunIsLast) // This was the last run, bail out
- {
- fIsLastLine = TRUE;
- break;
- }
- }
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::FindRunNewLine
- //----------------------------------------------------------------------------------------
-
- char* FW_CPrivTextBuffer::FindRunNewLine()
- {
- char* runLimit = fCurRun + fCurRunLen, *p = fCurRunPos;
- while (p < runLimit && *p != 0x0D)
- ++ p;
-
- return (p < runLimit) ? p : NULL;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::GetCurrentLine
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivTextBuffer::GetCurrentLine(const char*& pLine, FW_ByteCount& len)
- {
- pLine = fCurrentLine;
- len = fCurrentLineLength;
-
- if (fIsLastLine)
- fIsDone = TRUE;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::ResetBuffer
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivTextBuffer::ResetBuffer(FW_ByteCount size)
- {
- if(size <= kBufferSize)
- {
- // the fixed buffer is large enough; use it
- FW_CMemoryManager::FreeBlock(fDynamicBufferBase);
- fDynamicBufferBase = NULL;
- fCurrentBufferBase = fFixedBuffer;
- fCurrentBufferSize = kBufferSize;
- }
- else
- {
- // the fixed buffer is too small; allocate a dynamic buffer
- fDynamicBufferBase = (char*) FW_CMemoryManager::AllocateBlock(kBufferSize);
- fDynamicBufferSize = kBufferSize;
- fCurrentBufferBase = fDynamicBufferBase;
- fCurrentBufferSize = fDynamicBufferSize;
- }
-
- fCurrentLineLength = 0;
- fCurrentLine = fCurrentBufferBase;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::AppendToBuffer
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivTextBuffer::AppendToBuffer(const char* pch, FW_ByteCount cb)
- {
- if(fCurrentLineLength + cb <= fCurrentBufferSize)
- {
- // the buffer is still large enough, just stick the character in
- FW_PrimitiveCopyMemory(pch, fCurrentLine + fCurrentLineLength, cb);
- }
- else
- {
- // the buffer became too small
- if(fDynamicBufferBase == NULL)
- {
- // we are switching from a static to a dynamic buffer
- fDynamicBufferBase = (char*) FW_CMemoryManager::AllocateBlock(2 * kBufferSize);
- fDynamicBufferSize = 2 * kBufferSize;
- fCurrentBufferBase = fDynamicBufferBase;
- fCurrentBufferSize = fDynamicBufferSize;
-
- // copy the current contents into the dynamic buffer
- ::FW_PrimitiveCopyMemory(fFixedBuffer, fDynamicBufferBase, kBufferSize);
- }
- else
- {
- // just reallocate the dynamic buffer
- fDynamicBufferSize += kBufferSize;
- fDynamicBufferBase = (char*) FW_CMemoryManager::ResizeBlock(fDynamicBufferBase, fDynamicBufferSize);
- fCurrentBufferBase = fDynamicBufferBase;
- fCurrentBufferSize = fDynamicBufferSize;
- }
- }
-
- fCurrentLine = fCurrentBufferBase;
- fCurrentLineLength += cb;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::GetNextRun
- //----------------------------------------------------------------------------------------
-
- FW_Boolean FW_CPrivTextBuffer::GetNextRun()
- {
- FW_ASSERT(!fCurRunIsLast); // No advancing beyond last run!
- if (fString != NULL)
- {
- fCurRun = (char*)FW_PrivString_RevealBuffer(fString);
- fCurRunLen = FW_PrivString_GetByteLength(fString);
- fCurRunIsLast = TRUE;
- }
- else
- {
- FW_PrivTextReader_PeekRunAhead(fReader, (const char**) &fCurRun, &fCurRunLen);
-
- FW_ASSERT(fCurRun != NULL);
- FW_ASSERT(fCurRunLen != 0);
-
- //???JEL: I added the FW_SOMEnvironment and FW_FailOnEvError, but I'm not
- // certain this is a complete error handling stategy for this function.
- FW_SOMEnvironment ev;
- FW_PrivTextReader_Advance(fReader, ev, fCurRunLen);
- FW_FailOnEvError(ev);
-
- fCurRunIsLast = FW_PrivTextReader_GetPosition(fReader)
- >= FW_PrivTextReader_GetByteLength(fReader);
- }
-
- fCurRunPos = fCurRun;
- return fCurRunLen != 0;
- }
-
- //========================================================================================
- // Global Method FW_PrivGetStringSegment
- //========================================================================================
- //
- // Used by word-wrapping text measurement and drawing methods
- //
- // str - the string we're wrapping
- // len - length of the string
- // segStart - start of the segment that should be drawn
- // segLen - length of the segement that should be drawn
- // maxWidth - max width that the string can be when drawn
- // actualWidth - the actual width of the string
- // wordWrap - should we try to wrap text or just draw it in one piece
- // wordBreak - if the first word doesn't fit, should we break it?
-
- FW_Boolean FW_PrivGetStringSegment(
- ODPlatformCanvas platformCanvas,
- FW_Boolean& bCalledBefore,
- const char* str,
- FW_ByteCount len,
- FW_BytePosition& segStart,
- FW_ByteCount& segLen,
- FW_PlatformCoordinate maxWidth,
- FW_PlatformCoordinate& actualWidth,
- FW_Boolean wordWrap,
- FW_Boolean wordBreak)
- {
- enum
- {
- kSpace = ' ',
- kCR = 0x0D,
- kLF = 0x0A
- };
-
- segStart = 0;
- segLen = 0;
-
- // if we encountered an end-line during the previous call, "str" will point to a newline char
- if (bCalledBefore)
- {
- if (*str == kCR && len > 0)
- {
- str++;
- segStart++;
- len--;
- }
- if (*str == kLF && len > 0)
- {
- str++;
- segStart++;
- len--;
- }
- }
- bCalledBefore = TRUE;
-
- // skip the leading spaces
- while (*str == kSpace && len > 0)
- {
- str++;
- segStart++;
- len--;
- }
-
- if (len == 0)
- return FALSE;
-
- #ifdef FW_BUILD_WIN
- SIZE size;
- #endif
-
- if (!wordWrap)
- {
- // return the whole string in one chunk
- segLen = len;
- #ifdef FW_BUILD_WIN
- ::GetTextExtentPoint(platformCanvas, str, len, &size);
- actualWidth = size.cx;
- #endif
- #ifdef FW_BUILD_MAC
- FW_UNUSED(platformCanvas);
- actualWidth = ::TextWidth(Ptr(str), 0, len);
- #endif
- }
- else
- {
- // break the string into chunks
- FW_PlatformCoordinate accumWidth = 0;
- FW_PlatformCoordinate newWidth;
- FW_PlatformCoordinate wordWidth;
- const char* s = str;
- const char* wordEnd = NULL;
-
- segLen = 0;
-
- while (len > 0)
- {
- // check if we are at the end of a word
- if (*s == kSpace)
- {
- if (*(s - 1) != kSpace)
- {
- wordEnd = s;
- wordWidth = accumWidth;
- }
- }
-
- // check if we have a line terminator
- if (*s == kCR || *s == kLF)
- {
- wordEnd = s;
- wordWidth = accumWidth;
- break;
- }
-
- // add the current char width
- #ifdef FW_BUILD_WIN
- ::GetTextExtentPoint(platformCanvas, str, s - str + 1, &size);
- newWidth = size.cx;
- #endif
- #ifdef FW_BUILD_MAC
- newWidth = ::TextWidth(Ptr(str), 0, s - str + 1);
- #endif
- if (newWidth > maxWidth)
- break;
-
- accumWidth = newWidth;
-
- // advance to the next character
- s++;
- len--;
- }
-
- // the whole string fit just fine
- if (len == 0)
- {
- wordEnd = s;
- wordWidth = accumWidth;
- }
-
- // the first character was too wide
- if (s == str)
- {
- // ... but it was the first character, so draw it anyways!
- s++;
- len--;
- #ifdef FW_BUILD_WIN
- ::GetTextExtentPoint(platformCanvas, str, 1, &size);
- newWidth = size.cx;
- #endif
-
- #ifdef FW_BUILD_MAC
- newWidth = ::TextWidth(Ptr(str), 0, 1);
- #endif
- }
-
- // the first word didn't fit...
- if (wordEnd == NULL)
- {
- if (!wordBreak)
- {
- // it's not ok to break the first word, keep looking
- while (len > 0 && *s != ' ')
- {
- #ifdef FW_BUILD_WIN
- SIZE size;
- ::GetTextExtentPoint(platformCanvas, str, s - str + 1, &size);
- accumWidth = size.cx;
- #endif
- #ifdef FW_BUILD_MAC
- accumWidth = ::TextWidth(Ptr(str), 0, s - str + 1);
- #endif
- s++;
- len--;
- }
- }
-
- wordWidth = accumWidth;
- wordEnd = s;
- }
-
- segLen = wordEnd - str;
- actualWidth = wordWidth;
- }
-
- return TRUE;
- }
-